// TestJournalrecord.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include "TestJournalrecord.h"
#include "resource.h"
#include "iostream"
#include "fstream"
#include "string"

using namespace std;

#include "CmnHdr.h"

HINSTANCE g_hInst;
HHOOK g_Record;
HHOOK g_Play;

LRESULT CALLBACK JournalRecordProc(int code,WPARAM wParam,LPARAM lParam);
LRESULT CALLBACK JournalPlaybackProc(int code,WPARAM wParam,LPARAM lParam);
ofstream logs("C:\\Users\\Administrator\\Desktop\\logs.txt");
HWND _hwnd = 0, stop_hwnd=0;

struct EVENTMSG_NODE
{
	EVENTMSG msg;
	EVENTMSG_NODE *pNext;
};

EVENTMSG_NODE *g_pHead = NULL;
EVENTMSG_NODE *g_pEnd = NULL;

EVENTMSG_NODE *g_pLast;
EVENTMSG_NODE *g_pNext;

// Global Variables:
const TCHAR g_szAppName[] = _T("WinsowsPlayback");	// The application title text

// Forward declarations of functions included in this code module:
INT_PTR CALLBACK Dlg_Proc(HWND, UINT, WPARAM, LPARAM);
BOOL Dlg_OnInitDialog(HWND, HWND, LPARAM);
void Dlg_OnCommand(HWND, int, HWND, UINT);

// entry function
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
					   _In_opt_ HINSTANCE hPrevInstance,
					   _In_ LPTSTR    lpCmdLine,
					   _In_ int       nCmdShow)
{
	g_hInst = hInstance;
	UNREFERENCED_PARAMETER(hPrevInstance);
	INT_PTR nResult = DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_TESTJOURNALRECORD_DIALOG), 
		NULL, Dlg_Proc, _ttoi(lpCmdLine));
	return nResult;
}

//
//  FUNCTION: Dlg_Proc(HWND, UINT, WPARAM, LPARAM)
//
//  PURPOSE:  Message handler for Dialog box
//
INT_PTR CALLBACK Dlg_Proc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg)
	{
		chHANDLE_DLGMSG(hwndDlg, WM_INITDIALOG, Dlg_OnInitDialog);
		chHANDLE_DLGMSG(hwndDlg, WM_COMMAND, Dlg_OnCommand);
		case WM_CLOSE:
			DestroyWindow(hwndDlg);
			break;
		case WM_DESTROY:
			PostQuitMessage(0);
	}
	return FALSE;
}

//
//  FUNCTION: Dlg_OnInitDialog(HWND, HWND, LPARAM)
//
//  PURPOSE:  Initialize the dialog box.
//
BOOL Dlg_OnInitDialog(HWND hwndDlg, HWND hwndFocus, LPARAM lParam)
{
	// Sets the dialog box icons
	chSETDLGICONS(hwndDlg, IDI_TESTJOURNALRECORD);
	
	EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_RECORD), TRUE);
	EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_STOP), FALSE);
	EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_PLAYBACK), FALSE);
	_hwnd = hwndDlg;
	return TRUE;
}

//
//  FUNCTION: Dlg_OnCommand(HWND, int, HWND, UINT)
//
//  PURPOSE:  Command message handler for dialog box
//
void Dlg_OnCommand(HWND hwndDlg, int id, HWND hwndCtl, UINT codeNotify)
{
	switch (id)
	{
	case IDC_BTN_RECORD:
		{	
			_hwnd = GetForegroundWindow();
			ShowWindow(_hwnd, SW_MINIMIZE);
			g_Record = SetWindowsHookEx(WH_JOURNALRECORD, JournalRecordProc, g_hInst, 0);
			if (NULL == g_Record)
			{
				MessageBox(NULL,"Fail", "hook", MB_OK);
			}
			else
			{
				EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_RECORD), FALSE);
				EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_STOP), TRUE);
				EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_PLAYBACK), FALSE);
				
			}
		}
		break;
	case IDC_BTN_PLAYBACK:
		{
			g_pLast = g_pHead;
			g_pNext = g_pHead;
			g_Play = SetWindowsHookEx(WH_JOURNALPLAYBACK, JournalPlaybackProc, g_hInst, 0);
			EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_RECORD), TRUE);
			EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_STOP), FALSE);
			EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_PLAYBACK), FALSE);
		}
		break;
	case IDC_BTN_STOP:
		{	

			EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_RECORD), FALSE);
			EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_STOP), FALSE);
			EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_PLAYBACK), TRUE);
			UnhookWindowsHookEx(g_Record);	
			logs.close();
		}
		break;
	default:break;
	}
}

LRESULT CALLBACK JournalRecordProc(int code,WPARAM wParam,LPARAM lParam)
{
	
	if (code < 0)
	{
		CallNextHookEx(g_Record, code, wParam, lParam);
	}

	if (HC_ACTION == code)
	{
		
		EVENTMSG_NODE *pNew = new EVENTMSG_NODE;
		//if (((LPEVENTMSG)(lParam))->message == 512)
		//{
			//return CallNextHookEx(g_Record, code, wParam, lParam);
		//}
		pNew->pNext = NULL;
		pNew->msg.hwnd = ((LPEVENTMSG)(lParam))->hwnd;
		pNew->msg.message = ((LPEVENTMSG)(lParam))->message;
		pNew->msg.paramH = ((LPEVENTMSG)(lParam))->paramH;
		pNew->msg.paramL = ((LPEVENTMSG)(lParam))->paramL;
		pNew->msg.time = ((LPEVENTMSG)(lParam))->time;
		
		
		// write logs
		logs << "hwnd " << pNew->msg.hwnd << endl;
		logs << "message " << pNew->msg.message << endl;
		logs << "paramH " << pNew->msg.paramH << endl;
		logs << "paramL " << pNew->msg.paramL << endl;
		logs << "time " << pNew->msg.time << endl;
		logs << endl;

		if (NULL == g_pHead)
		{
			g_pHead = pNew;
		}
		else
		{
			g_pEnd->pNext = pNew;
		}

		g_pEnd = pNew;

	}
	
	return CallNextHookEx(g_Record, code, wParam, lParam);
}

void Clear()
{
	if (NULL != g_pHead)
	{
		EVENTMSG_NODE *pTemp = g_pHead;
		while (NULL != pTemp)
		{
			g_pHead = pTemp->pNext;
			delete pTemp;
			pTemp = g_pHead;
		}
	}
}
/*
void Load()
{
	if (NULL != g_pHead)
	{
		ifstream in("1.txt");
		string filename;
		string line;
		int count = 1;
		EVENTMSG_NODE* pTemp = g_pHead->pNext;
		EVENTMSG_NODE* pcur = pTemp;
		if (in)
		{
			while (getline(in, line))
			{
				pTemp = pTemp->pNext;
				pcur = pTemp;
				while (NULL != pTemp)
				{
					switch (count)
					{
					case 1:
						{
							int nHwnd = atoi((LPCTSTR)line);
							HWND hWnd = (HWND)nHwnd;
							pTemp->msg.hwnd = hWnd;
						}
						break;
					case 2:
						{
							pTemp->msg.message = atoi(line.c_str());
						}
						break;
					case 3:
						{
							pTemp->msg.paramH = atoi(line.c_str());
						}
						break;
					case 4:
						{
							pTemp->msg.paramL = atoi(line.c_str());
						}
						break;
					case 5:
						{
							pTemp->msg.paramL = StringToDword(line);
						}
					break;
					default: break;
					}				
				}
			}
		}
		else
		{
			cout << "no such file" << endl;
		}
	}
}



DWORD StringToDword(string val)
{
	DWORD cur_dword;
	sscanf(val.c_str(), "%ul", &cur_dword);
	return cur_dword;
}
*/

LRESULT CALLBACK JournalPlaybackProc(int code,WPARAM wParam,LPARAM lParam)
{
	DWORD dwTime = 0;
	
	
	switch (code)
	{
		case HC_GETNEXT:
			{
				if (g_pLast->msg.hwnd != GetDlgItem(_hwnd, IDC_BTN_STOP))
				{
					ShowWindow(g_pLast->msg.hwnd, SW_MAXIMIZE);
				}
				LPEVENTMSG pEvent = (LPEVENTMSG)lParam;
				pEvent->hwnd = g_pLast->msg.hwnd;
				pEvent->message = g_pLast->msg.message;
				pEvent->paramH = g_pLast->msg.paramH;
				pEvent->paramL = g_pLast->msg.paramL;
				pEvent->time = g_pLast->msg.time;
				
				//SendMessage(pEvent->hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, pEvent->paramL);


				dwTime = (g_pNext->msg.time - g_pLast->msg.time)*1.5;

				if (dwTime < 0)
				{
					dwTime = 1;
				}
				
				if (g_pLast != g_pNext)
				{
					g_pLast = g_pNext;
				}

				return dwTime;
			}
		case HC_SKIP:
			{
				if (NULL == g_pNext->pNext)
				{
					Clear();
					return UnhookWindowsHookEx(g_Play);
				}

				g_pNext = g_pNext->pNext;
				return 0;
			}
		default:
			break;
	}
	
	return CallNextHookEx(g_Play, code, wParam, lParam);
}